#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright 2007 Denis Kürov
# Licensed under the GNU General Public License, version 3.
# See the file http://www.gnu.org/copyleft/gpl.txt.

import os

def flush_child(sender, instance, signal, *args,**kwargs):
    """ That one is needed for tcp,udp,icmp,options,prefixes"""
    from iptables.dbwork.rulegen import IptablesRunner

    if not instance.parent_rule.loaded:
            return
        
    #flush the current chain you need
    IptablesRunner.flush_signal(chain_name=instance.parent_rule.parent_chain.name)
    
    

def remove_rule_action(sender, instance, signal, *args,**kwargs):
    """ When we delete a rule the order in LoadIndex shouldnt be destroyed
    nasil olacak sender instance id sine gore  yuklu mu degil mi kontrol edeck dogru ise
    bu durumda LoadIndexteki entry silinsin ve loglansin"""
    #for logging the events
    from iptables.dbwork.ruleorder import RuleLoadOrder
    from iptables.forms.fireutil import AktiviteKaydet
    from iptables.dbwork.rulegen import IptablesRunner
    
    if instance.loaded:
        
        #logger staff
        ak=AktiviteKaydet(u"Kural silindi,yuklenmisi de silmek gerekir!")
        ak.dosya_ac()
        
        loader=instance.loadindex_set.all()
        
        if loader:
            r=RuleLoadOrder()
            del_res=r.delete_order(instance.id)
            
            if del_res:
                ak.set_durum(u"Basarili")
                
            else:
                ak.set_durum(u"Olmadi")
                
        #the log actions
        ak.set_extra(kural_adi=instance.name)
        ak.log_activity()
        ak.dosya_kapa()
        

def unload_rule(sender, instance, signal, *args,**kwargs):
    """ When the rule is loaded and when unload it we should remove the entry from LoadIndex thing
    without destroying the order of the rules"""
    
    from iptables.forms.fireutil import AktiviteKaydet
    from iptables.dbwork.ruleorder import RuleLoadOrder
    
    
    import os
    
    
    if not instance.loaded:
        
        #onceki durum True olmasi gerekir.
        previous=sender.objects.filter(id=instance.id)
        
        #if it was there and was True before
        if previous and previous[0].loaded:
            
        
            #get loaded rules
            loader=instance.loadindex_set.filter(parent_rule=instance.id)
            
            if loader :
                ak=AktiviteKaydet(u"Kural unload yapıldı!")
                ak.dosya_ac()
                
                r=RuleLoadOrder()
                del_res=r.delete_order(instance.id)
                
                if del_res:
                    #errors={}
                    #the actual deleting part
                    #rule_execute=os.popen3("".join(["sudo ",del_res]))
                    
                    #error=rule_execute[2].read() or None
                    
                    #if error :
                        
                        #ak.set_durum(u"Basarisiz")
                        #errors["kural_silme"]="".join(["Kural silerken hata :\n",error])
                    ak.set_durum(u"Basarili")
                else:
                    ak.set_durum(u"Olmadi")
                    
                #ak.set_extra(hatalar=errors)
                ak.log_activity()
                ak.dosya_kapa()
                
            else:
                return
                    
                
        else:
            return
            
        
        
        
        
    else:
        return
    

def new_iptables_entry(sender,instance,signal,*args,**kwargs):
    """ When you insert something new to the LoadIndex we must update the memory ruleset
    one of the hardest parts of the project :) hard is good"""
    
    from iptables.forms.fireutil import AktiviteKaydet
    from iptables.dbwork.rulegen import RuleGenerator
    from iptables.dbwork.rulegen import IptablesRunner
    
    loaded_id=instance.id
    errors={}
    #is it a new entry ??
    result=sender.objects.filter(id=loaded_id)
    
    if result :
        #do not do anything
        return
    
    #get the chain name of the rule :
    
    #that one is for the ones that are smaller than it
    small=[]
    
    chain_name=instance.parent_rule.parent_chain.name
    
    #get smaller numbers :
    brothers=sender.objects.filter(ordering__lt=instance.ordering)
    
    for i in brothers:
        if i.parent_rule.parent_chain.name==chain_name:
            #append them to the list...
            #print i.parent_rule.name
            small.append(i)
    
    #the initial order for that rule
    my_order=len(small)
    
    #print small
    
    if small:
        for rule in small :
            #some have log entry so we must control it
            if rule.parent_rule.prefixer_set.all():
                #print "The rule : %s has log"%(rule.parent_rule.name)
                my_order +=1
                
            #my_order +=1
    
    #print "There are %s rulezzz"%(my_order)        
    #!!!!burada iptables -l için bir kontrol olacak eğer fail olursa flush set olacak...
    #heee evet olabilir tabii :)
    
    rules=[]   
    r=RuleGenerator()
    
    log=instance.parent_rule.prefixer_set.all()
    
    if log:
        
        my_order+=1
        rules.append(r.create_rule(instance.parent_rule.id,action="insert",insert_num=my_order,log=True))
        
    my_order+=1    
    rules.append(r.create_rule(instance.parent_rule.id,action="insert",insert_num=my_order,log=False))
    
    ak=AktiviteKaydet(u"LoadIndex kümesine yeni eleman eklendi!")
    ak.dosya_ac()
    
    if rules:    
        ak.set_kural("\n".join(["%s"%(i) for i in rules]))
    
    #execute them
    for r in rules :
        rule_execute=os.popen3("".join(["sudo ",r]))
        error=rule_execute[2].read() or None
        
        if error :
            ak.set_durum(u"Basarisiz")
            errors["".join(["kural_ekleme",rules.index(r)])]="".join(["Kural eklerken hata :\n",error])
    
        else:
            ak.set_durum(u"Superr!")
    
    #print "###################################################"
    #log all the things
    #ak.set_durum("Basari")
    ak.set_extra(hatalar=errors)
    ak.log_activity()
    ak.dosya_kapa()    
    
    if error :
        #flush all the things dont like the errors ..
        IptablesRunner.flush_signal()
    
    
    #hacky
    hacky=open("hacky.txt","w")
    hacky.write("insert")
    hacky.close()
    #hacky
        
def remove_iptables_entry(sender,instance,signal,*args,**kwargs):
    """ When we delete something from LoadInedex it should also effect the memory set rulez"""
    
    from iptables.forms.fireutil import AktiviteKaydet
    from iptables.dbwork.rulegen import RuleGenerator
    from iptables.dbwork.rulegen import IptablesRunner
    
    errors={}
    #hacky kontrolü yap
    if os.path.exists("hacky.txt"):
        hacky=open("hacky.txt","r")
        if_rule=hacky.read().strip()
        hacky.close()
        
    
        r=RuleGenerator()
        
        curent_rule=r.create_rule(instance.parent_rule.id,action="delete",insert_num=None,log=False)
        
        if curent_rule==if_rule:
            return
        
        chain_delete=if_rule.split()
        if len(chain_delete)==3 and chain_delete[1].strip()=='-X' and chain_delete[2].strip()==instance.parent_rule.parent_chain.name:
            return
        
    else:
        r=RuleGenerator()
        
        curent_rule=r.create_rule(instance.parent_rule.id,action="delete",insert_num=None,log=False)
        
    ak=AktiviteKaydet(u"LoadInedx kural sildi iptablesa yansıt")
    ak.dosya_ac()
    
    
    # to run them
    rules=[]
    #get the unloaded rule's parent id and see if it is logged
    log=instance.parent_rule.prefixer_set.all()
    
    if log:
        rules.append(r.create_rule(instance.parent_rule.id,action="delete",insert_num=None,log=True))
        
    rules.append(curent_rule)
    
    if rules:    
        ak.set_kural("\n".join(["%s"%(i) for i in rules]))
    
    #buraya hata olursa diye bir tane kontrol koyacazzz ??
    
    for r in rules :
        rule_execute=os.popen3("".join(["sudo ",r]))
        error=rule_execute[2].read() or None
        
        if error :
            ak.set_durum(u"Basarisiz")
            errors["".join(["kural_silme",str(rules.index(r))])]="".join(["Kural silerken hata :\n",error])
        
        else:
            ak.set_durum(u"Superr!")
    #log the activities.    
    
    ak.set_extra(hatalar=errors)
    ak.log_activity()
    ak.dosya_kapa()    
    
    if error :
        #flush all the things dont like the errors ..
        IptablesRunner.flush_signal()
    
    #print rules
    hacky=open("hacky.txt","w")
    if len(rules)==2:
        hacky.write(str(rules[1]))
    else:
        hacky.write(str(rules[0]))
    
    hacky.close()
        
    

def del_iptables_chain (sender, instance, signal, *args,**kwargs):
    """ Deleting from iptables memory"""
    from iptables.forms.fireutil import AktiviteKaydet
    from iptables.dbwork.rulegen import RuleGenerator
    from iptables.dbwork.rulegen import IptablesRunner
    
    errors={}
    ak=AktiviteKaydet(u"Bir zincir silindi !")
    ak.dosya_ac()
    
    r=RuleGenerator()
    
    rule =r.create_new_chain(instance.id,action="del_c")
    
    rule_execute=os.popen3("".join(["sudo ",rule]))
    error=rule_execute[2].read() or None
    
    if error :
        ak.set_durum(u"Basarisiz")
        errors["chain_silme"]="".join(["Kural silerken hata :\n",error])
    
    else:
        ak.set_durum(u"Superr!")
    
    if rule:    
        ak.set_kural(rule)
    
    #buraya hata olursa diye bir tane kontrol koyacazzz ??
    
    #log the activities.    
    ak.set_extra(hatalar=errors)
    ak.log_activity()
    ak.dosya_kapa()    
    
    if error :
        #flush all the things dont like the errors ..
        IptablesRunner.flush_signal()
    
    
    hacky=open("hacky.txt","w")
    hacky.write(str(rule))
    hacky.close()
        

def start_flush(signal, *args,**kwargs):
    """ The starting point flush when you call the syncdb 
    It will be done like that :
    1) Check if you have the main target and chains in your db
    2) Add the related and established to INPUT and OUTPUT
    3) Let the web thing to acess (that interface)
    4) Flush the iptables ands set the policies
    5) Run the rules important (latest step)"""
    
    from iptables.models import Chain, Target,Rule,Optional
    from iptables.dbwork.rulegen import IptablesRunner
    from iptables.dbwork.ruleorder import RuleLoadOrder
    #step 1 
    for chain in ['INPUT','OUTPUT','FORWARD']:
        is_there= Chain.objects.filter(name=chain)
        
        if not is_there:
            #insert here the rule
            c=Chain(name=chain,description=u'That is one of the core chains in iptables it is needed')
            c.save()
            
    
    print "Chain thing handled"
    
    for target in ['DROP','ACCEPT','REJECT']:
        is_there = Target.objects.filter(name=target)
        
        if not is_there :
            #here insert the target
            t=Target(name=target,description=u'That is one of the core tagets in iptables it is needed')
            t.save()
         
    print "Target thing handled"
    #step 2 the rule we want is like that :
    
    #get the ACCEPT target
    accept_taget=Target.objects.get(name="ACCEPT")
    
    #get the INPUT and OUTPUT chain
    input_chain=Chain.objects.get(name="INPUT")
    output_chain=Chain.objects.get(name="OUTPUT")
    
    r=Rule.objects.filter(parent_chain=input_chain.id,parent_target=accept_taget.id,sip='a,0.0.0.0/0',dip='a,0.0.0.0/0',s_interface='eth0',d_interface='any',loaded=True)
    print r
    if not r:
        #create the rule here
        r_create=Rule(name=u"input-relate-izin",parent_target=accept_taget,parent_chain=input_chain,sip='a,0.0.0.0/0',dip='a,0.0.0.0/0',s_interface='eth0',d_interface='any',loaded=True)
        r_create.save()
        op_create=Optional(parent_rule=r_create,ctstaus='ESTABLISHED,RELATED',mlength='0',mlimit='0',mac='0',state='0')
        op_create.save()
        
        r=RuleLoadOrder()
        r.insert_order(str(r_create.id),ordernum='last')
        print "we came here"
    else:
        
        o=Optional.objects.filter(parent_rule=r[0].id,ctstaus='ESTABLISHED,RELATED',mlength='0',mlimit='0',mac='0',state='0')
        
        if not o :
            #create the rule here
            r_create=Rule(name=u"input-relate-izin",parent_target=accept_taget,parent_chain=input_chain,sip='a,0.0.0.0/0',dip='a,0.0.0.0/0',s_interface='eth0',d_interface='any',loaded=True)
            r_create.save()
            op_create=Optional(parent_rule=r_create,ctstaus='ESTABLISHED,RELATED',mlength='0',mlimit='0',mac='0',state='0')
            op_create.save()
            
            r=RuleLoadOrder()
            r.insert_order(str(r_create.id),ordernum='last')
         
    print "input related handled"
    
    # the output part here      
    r=Rule.objects.filter(parent_chain=output_chain.id,parent_target=accept_taget.id,sip='a,0.0.0.0/0',dip='a,0.0.0.0/0',s_interface='any',d_interface='eth0',loaded=True)
    if not r:
        #create the rule here
        r_create=Rule(name=u"output-relate-izin",parent_target=accept_taget,parent_chain=output_chain,sip='a,0.0.0.0/0',dip='a,0.0.0.0/0',s_interface='any',d_interface='eth0',loaded=True)
        r_create.save()
        op_create=Optional(parent_rule=r_create,ctstaus='ESTABLISHED,RELATED',mlength='0',mlimit='0',mac='0',state='0')
        op_create.save()
        
        r=RuleLoadOrder()
        r.insert_order(str(r_create.id),ordernum='last')
    else:
        
        o=Optional.objects.filter(parent_rule=r[0].id,ctstaus='ESTABLISHED,RELATED',mlength='0',mlimit='0',mac='0',state='0')
        
        if not o :
            #create the rule here
            r_create=Rule(name=u"output-relate-izin",parent_target=accept_taget,parent_chain=output_chain,sip='a,0.0.0.0/0',dip='a,0.0.0.0/0',s_interface='any',d_interface='eth0',loaded=True)
            r_create.save()
            op_create=Optional(parent_rule=r_create,ctstaus='ESTABLISHED,RELATED',mlength='0',mlimit='0',mac='0',state='0')
            op_create.save()
            
            r=RuleLoadOrder()
            r.insert_order(str(r_create.id),ordernum='last')
    
    print "output related hadled"
    
    #now insert the part that gives premission to the localhost to be accessed
    r=Rule.objects.filter(parent_chain=input_chain.id,parent_target=accept_taget.id,sip='a,0.0.0.0/0',dip='a,0.0.0.0/0',s_interface='lo',d_interface='any',loaded=True)
    if not r:
        #create the rule here
        r_create=Rule(name=u"web-interface",parent_target=accept_taget,parent_chain=input_chain,sip='a,0.0.0.0/0',dip='a,0.0.0.0/0',s_interface='lo',d_interface='any',loaded=True)
        r_create.save()
        
        r=RuleLoadOrder()
        r.insert_order(str(r_create.id),ordernum='last')
        
    r=Rule.objects.filter(parent_chain=output_chain.id,parent_target=accept_taget.id,sip='a,0.0.0.0/0',dip='a,0.0.0.0/0',s_interface='any',d_interface='lo',loaded=True)
    if not r:
        #create the rule here
        r_create=Rule(name=u"web-interface-out",parent_target=accept_taget,parent_chain=output_chain,sip='a,0.0.0.0/0',dip='a,0.0.0.0/0',s_interface='any',d_interface='lo',loaded=True)
        r_create.save()
        
        r=RuleLoadOrder()
        r.insert_order(str(r_create.id),ordernum='last')
        
    print "web interface done"
    #First flush the rule 
    import os
    from confplace import FWALL_PATH
    
    os.popen3("".join(['sudo ',FWALL_PATH," -F"]))
    
    print "flushed iptables"
    #set the policy i may change the output thing
    for chain in ['INPUT','OUTPUT','FORWARD']:
        os.popen3("".join(['sudo ',FWALL_PATH," -P ",chain,' DROP']))
        
    print "policy set"
    #finally load all the things that are in db ...
    IptablesRunner.flush_signal()
    
    print "Rules loaded!"
